/*
** nfi.c  - Interpretador do arquivo neutro
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
//#include <hash_map>
//#include <hash>

#include "shape/nfi.h"
#include "auxiliary/auxFunc.h"
#include "hash.h"

// using namespace std;
// using namespace __gnu_cxx;

/*
** ---------------------------------------------------------------------
**                      Local Definitions
*/

#define MAX(a,b)                    (((a)>(b))?(a):(b))
#define ProcessError(f,s)           return Error(f,s,__FILE__,__LINE__)
#define isequal(s1,s2)              (strcmp(s1,s2) == 0)
#define DispTableSize(arr)          ((unsigned int)(sizeof(arr)/sizeof(arr[0])))
#define DispTableOffset(type,field) ((unsigned int)&(((type)NULL)->field))


typedef int handler(FILE *f);
 
typedef struct {
    char   *label ;
    handler *ptr_funcs ;
} DispTableRec;

struct eqstr
{
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1, s2) == 0;
  }
};

static TMesh3D *ptr_mesh;

/*
** ---------------------------------------------------------------------
**                 Static Functions Prototypes:
*/

static int   ReadString (FILE *f, char *s);
static int   NextLabel (FILE *f,  char *label);
static int   Error (char *function, char *message, char *file, int line);
static int   InitDispTable ( void );
static int   DispatchProcess ( FILE *f );
static int   EndDispTable ( void );

/*  Header */
static int   ProcessHeader(FILE *f);
static int   ProcessHeaderVersion (FILE *f);
static int   ProcessHeaderTitle (FILE *f);
static int   ProcessHeaderDate (FILE *f);


/* Nodes */
static int   ProcessNode (FILE *f);
static int   ProcessNodeCoord (FILE *f);
static int   ProcessNodeSupport (FILE *f);

/* Material */
static int   ProcessMaterial (FILE *f);
static int   ProcessMaterialLabel (FILE *f);
static int   ProcessMaterialIsothotropic (FILE *f);

/* 3D element */
static int   ProcessElement (FILE *f);
static int   ProcessTetr4 (FILE *f);
static int   ProcessTetr10 (FILE *f);
static int   ProcessBrick8 (FILE *f);
static int   ProcessBrick20 (FILE *f);

/* Load */
static int   ProcessLoad (FILE *f);                         
static int   ProcessLoadCase (FILE *f);
/* Nodal Load */
static int   ProcessLoadNodalForce (FILE *f);
/* Area Load */
static int   ProcessLoadAreaPressureUniform (FILE *f);
static int   ProcessLoadAreaPressureVariable (FILE *f);

/* Results */
static int   ProcessResult (FILE *f);
static int   ProcessResultCase (FILE *f);
static int   ProcessResultCaseStep (FILE *f);
/* process result scalar */
static int   ProcessResultElemNodalScalar (FILE *f);
static int   ProcessResultElemNodalScalarData (FILE *f);
static int   ProcessResultElemGaussScalar (FILE *f);
static int   ProcessResultElemGaussScalarData (FILE *f);

static int   ProcessEnd (FILE *f);



/*
** ---------------------------------------------------------------------
**                      Global variables:
*/



/*
** ---------------------------------------------------------------------
**                      Local variables:
*/


static char       funcname[256];
static int        status;
static DsHash<char*, handler *> *nftable;
static int        flag_header;

//static hash_map <char*, handler *, hash <char*>, eqstr> nftable2;


static  DispTableRec  NfDispTable[] = {
/******** Header ********/
  { "HEADER",                              ProcessHeader },
  { "HEADER.VERSION",                      ProcessHeaderVersion },
  { "HEADER.TITLE",                        ProcessHeaderTitle },
  { "HEADER.DATE",                         ProcessHeaderDate },

  { "NODE",                  ProcessNode },
  { "NODE.COORD",            ProcessNodeCoord },
  { "NODE.SUPPORT",          ProcessNodeSupport },
/******** Material ********/
  { "MATERIAL",             ProcessMaterial },
  { "MATERIAL.LABEL",       ProcessMaterialLabel },
  { "MATERIAL.ISOTROPIC",   ProcessMaterialIsothotropic },

/******** Elemets *********/
  { "ELEMENT",               ProcessElement },
  { "ELEMENT.TETR4",         ProcessTetr4 },
  { "ELEMENT.TETR10",        ProcessTetr10 },
  { "ELEMENT.BRICK8",        ProcessBrick8 },
  { "ELEMENT.BRICK20",       ProcessBrick20 },

/******** Loads *********/
 { "LOAD",                                 ProcessLoad },
 { "LOAD.CASE",                            ProcessLoadCase },
 { "LOAD.CASE.NODAL.FORCES",               ProcessLoadNodalForce },
 { "LOAD.CASE.NODAL.FORCE",                ProcessLoadNodalForce },
 { "LOAD.CASE.AREA.PRESSURE.UNIFORM",      ProcessLoadAreaPressureUniform },
 { "LOAD.CASE.AREA.UNIFORM",               ProcessLoadAreaPressureUniform },
 { "LOAD.CASE.AREA.PRESSURE.VARIABLE",     ProcessLoadAreaPressureVariable },
 { "LOAD.CASE.AREA.VARIABLE",              ProcessLoadAreaPressureVariable },

/******** Results *********/
 { "RESULT",                               ProcessResult },
 { "RESULT.CASE",                          ProcessResultCase },
 { "RESULT.CASE.STEP",                     ProcessResultCaseStep },
/* Scalar */
 { "RESULT.CASE.STEP.ELEMENT.NODAL.SCALAR",      ProcessResultElemNodalScalar },
 { "RESULT.CASE.STEP.ELEMENT.NODAL.SCALAR.DATA", ProcessResultElemNodalScalarData },
 { "RESULT.CASE.STEP.ELEMENT.GAUSS.SCALAR",      ProcessResultElemGaussScalar },
 { "RESULT.CASE.STEP.ELEMENT.GAUSS.SCALAR.DATA", ProcessResultElemGaussScalarData },

 { "END",                ProcessEnd },
};


/*
** ---------------------------------------------------------------------
**                      Local Functions:
*/


/* ========================== ReadString ============================ */
/*
** This function read a string that must be delimited by '.
** Parameters:
**  f -> input file pointer.
**  s -> output string.
**
** Ex: 'one label'
**
** The function returns s[] = "one label", without '.
** Returns the value 1 if sucess and 0 if error.
*/
static int ReadString (FILE *f, char *s)
{
 int i, c;

 while ((c = fgetc(f)) != '\'')         /* finds first ' */
 {
  if (c == EOF)
   return 0;
 }
 for (i = 0; (c=fgetc(f)) != '\''; i++)  /* fill s until next ' */
 {
  if (c == EOF)
   return 0;
  s[i] = c;
 }
 s[i] = '\0';
 return 1;
}


/* =========================== NextLabel ============================ */
/*
** This functon find the next label in the file. The label is identified
** by the character %.
** Parameters:
**  f     -> input file pointer.
**  label -> output string.
**
** Ex: %NODE.COORD
**
** The function returns label[] = "NODE.COORD", without %.
** Returns the value 1 if sucess and 0 if error.
*/
static int NextLabel (FILE *f,  char *label)
{
 int c;

 while ((c = fgetc(f)) != '%')         /* finds next % */
 {
  // printf ("%c ", (char) c);
  if (c == EOF)
   return 0;
 }
 if (fscanf (f, "%s ", label) != 1)     /* scan label string */
  return 0;
 else
  return 1;
}


/* =========================== Error ================================ */

static int Error (char *function, char *message, char *file, int line)
{
 status = 0;
 printf("%s %s %s %d\n", function, message, file,line);
 return 0;
}


/* ========================= InitDispTable ========================== */

static int InitDispTable ( void )
{
 int i, size;

 size = DispTableSize(NfDispTable);
 nftable = new DsHash<char*, handler *>;
 for ( i=0; i < size; i++ ) 
   nftable->Set (NfDispTable[i].label, NfDispTable[i].ptr_funcs);

 return 1;
}


/* ======================= DispatchProcess ========================== */

static int DispatchProcess ( FILE *f )
{
 handler    *fc = NULL;
 char       label[256];

 if (NextLabel (f, label) == 0) 
 {
   return Error(funcname, "",__FILE__,__LINE__);
 }
 printf ("%s\n", label);
 fc = nftable->Get (label);
 if ( fc == NULL ) return 1 ;
 return fc(f);
}


/* ========================== EndDispTable ========================== */

static int EndDispTable ( void )
{
 delete nftable;
 return 1;
}


/* ========================= InsertHeader ============================== */

static int InsertHeader ( char *label_name, char *label_type, FILE *f )
{
 char    *tmp;
 char    label_value[256];

 fgets (label_value, 256, f);
 tmp = label_value;                                                        
 while(*tmp != '\n' ) { tmp++; }                                      
 *tmp = '\0';

// NfPutHeaderItem (label_name, label_type, label_value); 
 
 return 1;
}


/* ====================== ProcessHeader============================== */

static int ProcessHeader (FILE *f)
{    
 char    label_name[20] = {"HEADER"};
 char    label_type[20] = {"char"}; 

 if( !InsertHeader( label_name, label_type, f) )
   return 0;
 return 1;
}

/* ====================== ProcessHeaderVersion ====================== */

static int ProcessHeaderVersion (FILE *f)
{    
 char    label_name[20] = {"HEADER.VERSION"};
 char    label_type[20] = {"char"};

 if( !InsertHeader( label_name, label_type, f) )
   return 0;
 return 1;
}


/* ========================= ProcessHeaderDate ====================== */

static int ProcessHeaderDate (FILE *f)
{    
 char    label_name[20] = {"HEADER.DATE"};
 char    label_type[20] = {"char"};

 if( !InsertHeader( label_name, label_type, f ))
   return 0;
 return 1;
}

/* ====================== ProcessHeaderTitle ======================== */

static int ProcessHeaderTitle (FILE *f)
{
 char    label_name[20] = {"HEADER.TITLE"};
 char    label_type[20] = {"char"};

 if( !InsertHeader( label_name, label_type, f) )
   return 0;
 return 1;
}



/* ================================================================== */
/* ================================================================== */
/* =======================                 ========================== */
/* =======================    N O D E      ========================== */
/* =======================                 ========================== */
/* ================================================================== */
/* ================================================================== */


/* ======================== ProcessNode ============================= */

static int ProcessNode (FILE *f)
{           
 int n;

 strcpy(funcname,"ProcessNode");
 if (fscanf (f, "%d", &n) != 1)
   ProcessError(funcname, "error in reading node number");
 
 ptr_mesh->nnodes = n;

 return 1;
}


/* ====================== ProcessNodeCoord ========================== */

static int ProcessNodeCoord (FILE *f)
{
 int     i, n;

 strcpy(funcname,"ProcessNodeCoord");

 if (fscanf (f, "%d", &n) != 1)
   ProcessError(funcname, "error in reading node number");

 if ( n != ptr_mesh->nnodes )
   ProcessError(funcname, "Number of nodes have been redefined");

 ptr_mesh->nodes = new Tnode_data[n];

 /* read values in .pos file and insert them */
 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d %lf %lf %lf", 
     &ptr_mesh->nodes[i].id, &ptr_mesh->nodes[i].x, &ptr_mesh->nodes[i].y, &ptr_mesh->nodes[i].z) != 4)
     ProcessError(funcname, "error in reading node coordinates");
 }

 return 1;
}


/* ====================== ProcessNodeSupport ========================== */

static int ProcessNodeSupport (FILE *f)
{
 int     i, n;

 strcpy(funcname,"ProcessNodeSupport");

 if (fscanf (f, "%d", &n) != 1)
   ProcessError(funcname, "error in reading node support number");

 if ( n <= 0 )
   ProcessError(funcname, "Number of node supports must be greater than zero");

 if ( ptr_mesh->nnodes == 0 )
   ProcessError(funcname, "Label %NODE must be specified in Neutral File");

 ptr_mesh->nsupport = n;
 ptr_mesh->support = new Tsup_data[n];

 /* read values in .pos file and insert them */
 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d %d %d %d %d %d %d", 
                  &ptr_mesh->support[i].id, 
                  &ptr_mesh->support[i].dx, &ptr_mesh->support[i].dy, &ptr_mesh->support[i].dz, 
                  &ptr_mesh->support[i].rx, &ptr_mesh->support[i].ry, &ptr_mesh->support[i].rz) != 7)
     ProcessError(funcname, "error in reading node support restraineds");
 }
 
 return 1;
}



/* ================================================================== */
/* ================================================================== */
/* =======================                  ========================= */
/* =======================  M A T E R I A L ========================= */
/* =======================                  ========================= */
/* ================================================================== */
/* ================================================================== */


/* ======================== ProcessMaterial ========================== */

static int   ProcessMaterial (FILE *f)
{
 int    n;

 strcpy(funcname,"ProcessMaterial");

 fscanf (f, "%d", &n);
 if ( n <= 0 )
  ProcessError(funcname, "Size of table of Material\n must be greater than zero \n");

 ptr_mesh->nmaterial = n;
 ptr_mesh->mat = new Tmat_isotropic[n];
 return 1;
}


/* ======================== ProcessMaterialLabel ===================== */

static int   ProcessMaterialLabel (FILE *f)
{
 int   n, id, i;

 strcpy(funcname,"ProcessMaterialLabel");

 fscanf (f, "%d", &n);
 if ( n <= 0 ) return 1; /*
  ProcessError(funcname,
    "Size of table of MaterialLabel\n must be greater than zero \n"); */

 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d", &id) != 1)
     ProcessError(funcname, "Error on reading Material id data");
    
   if (fscanf (f, "%s", &ptr_mesh->mat[id-1].label) != 1 )
     ProcessError(funcname, "Error on reading Material Label data");
 }

 return 1;
}


/* ======================== ProcessMaterialIsothotropic ============== */

static int   ProcessMaterialIsothotropic (FILE *f)
{
 int   n, i,id;

 strcpy(funcname,"ProcessMaterialIsothotropic");

 fscanf (f, "%d", &n);
 if ( n <= 0 ) return 1;

 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d", &id) != 1)
     ProcessError(funcname, "Error on reading Material id data");

   if (fscanf (f, "%lf %lf", &ptr_mesh->mat[id-1].e, &ptr_mesh->mat[id-1].nu) != 2 )
     ProcessError(funcname, "Error on reading Material Isothotropic data");
 }

 return 1;
}

/* ================================================================== */
/* ================================================================== */
/* =======================                 ========================== */
/* =======================  E L E M E N T  ========================== */
/* =======================                 ========================== */
/* ================================================================== */
/* ================================================================== */


/* ======================== ProcessElement ========================== */

static int ProcessElement (FILE *f)
{
 int   n;

 strcpy(funcname,"ProcessElement");

 if (fscanf (f, "%d", &n) != 1)
   ProcessError(funcname, "error in reading element number");

 if ( n <= 0 )
   ProcessError(funcname, "Number of elements must be greater than zero");

 ptr_mesh->nelems = n;
 ptr_mesh->elems = new Telement_3d[n];

 return 1;
}

/* ======================= ProcessTetr4 ============================= */
static int ReadElement3D (FILE *f, int type, int nn)
{
 int  i, j, n, id, integ;
 
 sprintf(funcname,"ReadElement3D");

 if ( ptr_mesh->nelems == 0 )
   ProcessError(funcname, "Label %%ELEMENT must be specified in Neutral File");
 
 if (fscanf (f, "%d", &n) != 1)
   ProcessError(funcname, "error in reading number of elements ");

 if ( n <= 0 )
    ProcessError(funcname, "Number of elements must be greater than zero");

 /* get the attributes and connectity of elements */
 for (i = 0; i < n; i++)                                                 
 {
   if (fscanf (f, "%d", &id) != 1 )
     ProcessError(funcname, "error in reading id of element ");
   id = id - 1;
   ptr_mesh->elems[id].id   = id; 
   ptr_mesh->elems[id].type = type;
   ptr_mesh->elems[id].n    = nn;

   if (fscanf (f, "%d %d ", &ptr_mesh->elems[id].mat, &integ) != 2 )
     ProcessError(funcname, "error in reading attributes of element ");

   for(j = 0; j < nn; j++)
   {
     if (fscanf (f, "%d", &ptr_mesh->elems[id].inc[j]) != 1 )
       ProcessError(funcname, "error in reading incidence of element ");
                                                                         
     if (ptr_mesh->elems[id].inc[j] <= 0)
       ProcessError(funcname, "invalid value of incidence for element ");
  
     ptr_mesh->elems[id].inc[j]--;
   }
 }

 return 1;
}

/* ======================= ProcessTetr4 ============================= */

static int ProcessTetr4 (FILE *f)
{
 return( ReadElement3D (f, (int) NF_TETR4, 4) );
}


/* ======================= ProcessTetr10 ============================ */

static int ProcessTetr10 (FILE *f)
{
 return( ReadElement3D (f, (int) NF_TETR10, 10) );
}


/* ======================= ProcessBrick8 ============================ */

static int ProcessBrick8 (FILE *f)
{
 return( ReadElement3D (f, (int) NF_BRICK8, 8) );
}


/* ======================= ProcessBrick20 =========================== */

static int ProcessBrick20 (FILE *f)
{
 return( ReadElement3D (f, (int) NF_BRICK20, 20) );
}



/* ================================================================== */
/* ================================================================== */
/* =======================                 ========================== */
/* =======================    L O A D      ========================== */
/* =======================                 ========================== */
/* ================================================================== */
/* ================================================================== */


/* ========================= ReadNumObjects ========================== */
static int  ReadNumObjects( FILE *f, int *n )
{
 if (fscanf (f, "%d", n) != 1)
   return 0;
 if ( n <= 0 )
   return 0;
 return 1;
}


/* ========================= ProcessLoad ============================ */

static int   ProcessLoad (FILE *f)
{


 return 1;
}


/* ========================= ProcessLoadCase ========================== */

static int   ProcessLoadCase (FILE *f)
{
 return 1;
}

/* ====================== ProcessLoadNodalForce ======================= */

static int   ProcessLoadNodalForce (FILE *f)
{
 int     i, n;

 strcpy(funcname,"ProcessLoadNodalForce");

 if ( !ReadNumObjects (f, &n) )
   ProcessError(funcname, "error in reading LoadNodalForce number");
 
 ptr_mesh->nfnodal = n;
 ptr_mesh->fnodal  = new TNodalForce[n];

 /* read values in .pos file and insert into BD */
 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d %f %f %f %f %f %f",
                  &ptr_mesh->fnodal[i].id,
                  &ptr_mesh->fnodal[i].Fx, &ptr_mesh->fnodal[i].Fy, &ptr_mesh->fnodal[i].Fz, 
                  &ptr_mesh->fnodal[i].Mx, &ptr_mesh->fnodal[i].My, &ptr_mesh->fnodal[i].Mz) != 7)
     ProcessError(funcname, "error in reading LoadNodalForce");
 }

 return 1;
}


/* ===================== ProcessLoadAreaPressureUniform =================== */

static int   ProcessLoadAreaPressureUniform (FILE *f)
{
 int     i, n;

 strcpy(funcname,"ProcessLoadAreaPressureUniform");

 if ( !ReadNumObjects (f, &n) )
   ProcessError(funcname, "error in reading LoadAreaPressureUniform number");

 ptr_mesh->nupressure = n;
 ptr_mesh->upressure  = new TAreaPressureUniform[n];

 /* read values in .pos file and insert into BD */
 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d %d %d %d %d %f %f %f",
                  &ptr_mesh->upressure[i].id, &ptr_mesh->upressure[i].id_i, 
                  &ptr_mesh->upressure[i].id_j, &ptr_mesh->upressure[i].id_k, 
                  &ptr_mesh->upressure[i].key, &ptr_mesh->upressure[i].px, 
                  &ptr_mesh->upressure[i].py, &ptr_mesh->upressure[i].pz) != 8)
     ProcessError(funcname, "error in reading LoadAreaPressureUniform");
 }

 return 1;
}


/* ===================== ProcessLoadAreaPressureVariable =================== */

static int   ProcessLoadAreaPressureVariable (FILE *f)
{
 int     i, n;

 strcpy(funcname,"ProcessLoadAreaPressureVariable");

 if ( !ReadNumObjects (f, &n) )
   ProcessError(funcname, "error in reading LoadAreaPressureUniform number");

 ptr_mesh->nvpressure = n;
 ptr_mesh->vpressure  = new TAreaPressureVariable[n];

                                                                                  
 /* read values in .pos file and insert into BD */                                   
 for (i = 0; i < n; i++)
 {
   if (fscanf (f, "%d %d %d %d %d %f %f %f %f %f %f",
               &ptr_mesh->vpressure[i].id, &ptr_mesh->vpressure[i].id_i, &ptr_mesh->vpressure[i].id_j, 
               &ptr_mesh->vpressure[i].id_k, &ptr_mesh->vpressure[i].key, &ptr_mesh->vpressure[i].px1, 
               &ptr_mesh->vpressure[i].py1, &ptr_mesh->vpressure[i].pz1, &ptr_mesh->vpressure[i].px2, 
               &ptr_mesh->vpressure[i].py2, &ptr_mesh->vpressure[i].pz2) != 11) 
     ProcessError(funcname, "error in reading LoadAreaPressureVariable");
 }

 return 1;
}

/* ===================== ProcessResult =================== */

static int   ProcessResult (FILE *f)
{
  int  nrescases;

  strcpy(funcname,"ProcessResult");

  if (fscanf (f, "%d", &nrescases) != 1) 
    ProcessError(funcname, "error in reading nrescases number ");

  if (nrescases > 1)
    ProcessError(funcname, "number of case must be 1!");

  return 1;
}

/* ===================== ProcessResultCase =================== */

static int ProcessResultCase (FILE *f)
{
  int  curcase, nsteps;

  strcpy(funcname,"ProcessResultCase");

  if (fscanf (f, "%d %d", &curcase, &nsteps) != 2)
    ProcessError(funcname, "error in reading curcase and nsteps");

  if (nsteps > 1)
    ProcessError(funcname, "number of step must be 1!");

  return 1;
}

/* ===================== ProcessResultCaseStep =================== */

static int   ProcessResultCaseStep (FILE *f)
{
  int curstep;

  strcpy(funcname,"ProcessResultCaseStep");
  if (fscanf (f, "%d", &curstep) != 1) 
    ProcessError(funcname, "error in reading curstep");

  // open memory
  ptr_mesh->results = new nfResullt;
  ptr_mesh->results->ElementGauss = new ElemResult;
  ptr_mesh->results->ElementNodal = new ElemResult;
 
  return 1;
}


/* ========================== ProcessResultField ========================== */

static int ProcessResultField (FILE *f, char *func_name, ElemResult *ptr)
{
 int   i, nfields;

 strcpy(funcname, func_name);

 if ( fscanf (f, "%d", &nfields) != 1 || nfields <= 0)
   ProcessError(funcname, "Invalid number of fields");

 ptr->nfields = nfields;
 ptr->fields  = new nfField[nfields];

 for (i = 0; i < nfields; i++)
 {
   if (ReadString (f, ptr->fields[i].label) != 1)
     ProcessError(funcname, "error in reading label field data");
 }
                                                              
 return 1;                                                    
}

/* ===================== ProcessResultElemNodalScalar =================== */

static int   ProcessResultElemNodalScalar (FILE *f)
{
  char  func_name[50] = { "ProcessResultNodalScalar" };
  return ( ProcessResultField (f, func_name, ptr_mesh->results->ElementNodal) );
}

/* ===================== ProcessResultElemNodalScalarData =================== */

static int   ProcessResultElemNodalScalarData (FILE *f)
{
  int     i, j, k, n, id, nfields;

  strcpy (funcname,"ProcessResultElemNodalScalarData");

  if (fscanf (f, "%d", &n) != 1) 
      ProcessError(funcname, "error in reading element data number");

  if ( n != ptr_mesh->nelems )
    ProcessError(funcname,"Number of elements has been redefined");

  /* memory */
  ptr_mesh->results->ElementNodal->elemInfo = new nfElemInfo[n];
  nfElemInfo *curr_res = ptr_mesh->results->ElementNodal->elemInfo;
  nfields = ptr_mesh->results->ElementNodal->nfields;

  for (i = 0; i < n; ++i)
  {
    if ( fscanf ( f, "%d", &id ) != 1 || id > n) 
      ProcessError(funcname, "error in reading id data");

    curr_res[id-1].npts = ptr_mesh->elems[id-1].n;
    curr_res[id-1].values = new double*[curr_res[id-1].npts];

    for (j = 0; j < curr_res[id-1].npts; ++j)
    {
      curr_res[id-1].values[j] = new double [nfields];
      for (k = 0; k < nfields; ++k)
      {
        if ( fscanf ( f, "%lf", &(curr_res[id-1].values[j][k]) ) != 1 ) 
            ProcessError(funcname, "error in reading stress data");
      }
    } 
  } 

  return 1;
}

/* ===================== ProcessResultElemGaussScalar =================== */

static int   ProcessResultElemGaussScalar (FILE *f)
{
  char  func_name[50] = { "ProcessResultElemGaussScalar" };
  return ( ProcessResultField (f, func_name, ptr_mesh->results->ElementGauss) );
}


/* ===================== ProcessResultElemGaussScalarData =================== */

static int   ProcessResultElemGaussScalarData (FILE *f)
{
  int     i, j, k, n, id, ngp, nfields;

  strcpy (funcname, "ProcessResultElemGaussScalarData");

  if (fscanf (f, "%d", &n) != 1) 
      ProcessError(funcname, "error in reading element data number");

  if ( n != ptr_mesh->nelems )
    ProcessError(funcname,"Number of elements has been redefined");

  /* memory */
  ptr_mesh->results->ElementGauss->elemInfo = new nfElemInfo[n];
  nfElemInfo *curr_res = ptr_mesh->results->ElementGauss->elemInfo;
  nfields = ptr_mesh->results->ElementGauss->nfields;

  for (i = 0; i < n; ++i)
  {
    if ( fscanf ( f, "%d%d", &id, &ngp ) != 2 || id > n)
      ProcessError(funcname, "error in reading id and ngp data");

    curr_res[id-1].npts = ngp;
    curr_res[id-1].values = new double*[curr_res[id-1].npts];

    for (j = 0; j < curr_res[id-1].npts; ++j)
    {
      curr_res[id-1].values[j] = new double [nfields];
      for (k = 0; k < nfields; ++k)
      {
        if ( fscanf ( f, "%lf", &(curr_res[id-1].values[j][k]) ) != 1 ) 
            ProcessError(funcname, "error in reading stress data");
      }
    } 
  } 

  return 1;
}





/* ========================== ProcessEnd ============================ */

static int ProcessEnd (FILE *f)
{
  status = 1;
  return 0;
}

/* ========================== InitMaterial ============================ */

static void initMaterial ( )
{
  int i, k;

  for (i = 0; i < ptr_mesh->nmaterial; ++i)
  {
    double E  = ptr_mesh->mat[i].e;
    double nu = ptr_mesh->mat[i].nu;

    ptr_mesh->mat[i].C = (double **) calloc (6, sizeof (double *));
    for (k = 0; k < 6; k++)
      ptr_mesh->mat[i].C[k] = (double *) calloc (6, sizeof (double));

    ptr_mesh->mat[i].invC = (double **) calloc (6, sizeof (double *));
    for (k = 0; k < 6; k++)
      ptr_mesh->mat[i].invC[k] = (double *) calloc (6, sizeof (double));

    CMatrix    (E, E, E, nu, nu, nu, nu, nu, nu, ptr_mesh->mat[i].C);
    InvCMatrix (E, E, E, nu, nu, nu, nu, nu, nu, ptr_mesh->mat[i].invC);
  }
}

/* ------------------------------------------------------- */
static int NavieStringMatcher( char *T, char *P )
{
 int n = (int) strlen (T);
 int m = (int) strlen (P);
 int s, k, t;

 for (s = 0; s < n-m+1; s++)
 {
   t = 0;
   for (k = 0; k < m; k++)
   {
     if (P[k] == T[s+k])
       t++;
     else
       k = m;
   }
   if (t == m)
     return 1;
 }
 return 0;
}

/* ========================== InitMaterial ============================ */

void initFieldsPosition ( )
{
  int i, k;
  ElemResult *currResult;

  if (ptr_mesh->results == NULL)
    return;

    // check for gauss results
  for (k = 0; k < 2; ++k)
  {
    if (k == 0)
      currResult = ptr_mesh->results->ElementGauss;
    else
      currResult = ptr_mesh->results->ElementNodal;

    if (currResult != NULL)
    {
      for (i = 0; i < currResult->nfields; ++i)
      {
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_XX"))
          currResult->sxx = i;
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_YY"))
          currResult->syy = i;
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_ZZ"))
          currResult->szz = i;
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_XY"))
        {
          currResult->sxy = i;
          currResult->syx = i;
        }
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_YX"))
        {
          currResult->sxy = i;
          currResult->syx = i;
        }
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_XZ"))
        {
          currResult->sxz = i;
          currResult->szx = i;
        }
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_ZX"))
        {
          currResult->sxz = i;
          currResult->szx = i;
        }
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_YZ"))
        {
          currResult->syz = i;
          currResult->szy = i;
        }
        if (NavieStringMatcher (currResult->fields[i].label, "SIGMA_ZY"))
        {
          currResult->syz = i;
          currResult->szy = i;
        }
      }
    }
  }

}

/*
** ---------------------------------------------------------------------
**                      Exported Functions
*/

/* ======================== NfiInterp ========================== */

int NfiInterp (FILE *f, TMesh3D *mesh)
{
 ptr_mesh = mesh;

 InitDispTable();
 do {} while (DispatchProcess(f) != 0);
 EndDispTable();

 // init values
 if (status)
 {
   initMaterial ( );
   initFieldsPosition ( );   
 }

 return status;
}
